﻿using ICSharpCode.SharpZipLib.Checksum;
using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Publicuse.Util
{
    /// <summary>
    /// 压缩工具类
    /// </summary>
    public class ZipUtil
    {
        /// <summary>
        /// ZIP：压缩文件夹
        /// add yuangang by 2016-06-13
        /// </summary>
        /// <param name="DirectoryToZip">需要压缩的文件夹（绝对路径）</param>
        /// <param name="ZipedPath">压缩后的文件路径（绝对路径）</param>
        /// <param name="ZipedFileName">压缩后的文件名称（文件名，默认 同源文件夹同名）</param>
        /// <param name="IsEncrypt">是否加密（默认 加密）</param>
        public static void ZipDirectory(string DirectoryToZip, string ZipedPath, string ZipedFileName = "", bool IsEncrypt = false)
        {
            //如果目录不存在，则报错
            if (!System.IO.Directory.Exists(DirectoryToZip))
            {
                throw new System.IO.FileNotFoundException("指定的目录: " + DirectoryToZip + " 不存在!");
            }
            //文件名称（默认同源文件名称相同）
            string ZipFileName = string.IsNullOrEmpty(ZipedFileName) ? ZipedPath + "\\" + new DirectoryInfo(DirectoryToZip).Name + ".zip" : ZipedPath + "\\" + ZipedFileName + ".zip";

            using (System.IO.FileStream ZipFile = System.IO.File.Create(ZipFileName))
            {
                using (ZipOutputStream s = new ZipOutputStream(ZipFile))
                {
                    if (IsEncrypt)
                    {
                        //压缩文件加密
                        s.Password = "123456";
                    }
                    try
                    {
                        ZipSetp(DirectoryToZip, s, "");

                    }
                    catch (Exception ex)
                    {

                    }
                }
            }
        }
        /// <summary>
        /// 递归遍历目录
        /// add yuangang by 2016-06-13
        /// </summary>
        private static void ZipSetp(string strDirectory, ZipOutputStream s, string parentPath)
        {
            if (strDirectory[strDirectory.Length - 1] != Path.DirectorySeparatorChar)
            {
                strDirectory += Path.DirectorySeparatorChar;
            }
            Crc32 crc = new Crc32();

            string[] filenames = Directory.GetFileSystemEntries(strDirectory);

            var index = 0;
            foreach (string file in filenames)// 遍历所有的文件和目录
            {

                if (Directory.Exists(file))// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
                {
                    string pPath = parentPath;
                    pPath += file.Substring(file.LastIndexOf("\\") + 1);
                    pPath += "\\";
                    ZipSetp(file, s, pPath);
                }

                else // 否则直接压缩文件
                {
                    if (index == 0)
                        continue;

                    //打开压缩文件
                    using (FileStream fs = File.OpenRead(file))
                    {
                        byte[] buffer = new byte[fs.Length];
                        fs.Read(buffer, 0, buffer.Length);

                        string fileName = parentPath + file.Substring(file.LastIndexOf("\\") + 1);
                        ZipEntry entry = new ZipEntry(fileName);

                        entry.DateTime = DateTime.Now;
                        entry.Size = fs.Length;

                        fs.Close();

                        crc.Reset();
                        crc.Update(buffer);

                        entry.Crc = crc.Value;
                        s.PutNextEntry(entry);

                        s.Write(buffer, 0, buffer.Length);
                    }
                }
            }
        }

        /// <summary>
        /// 压缩ZIP方法
        /// </summary>
        /// <param name="topDirName">路径</param>
        /// <param name="fileNameToZip">压缩后文件名</param>
        /// <param name="ZipedFileName">被压缩文件名</param>
        /// <param name="CompressionLevel">级别，9最好,1最快</param>
        /// <param name="password">密码</param>
        /// <param name="comment">描述？？</param>
        public static void ZipFile(string topDirName, string[] fileNameToZip, string ZipedFileName, int CompressionLevel, string password, string comment)
        {
            DateTime time = DateTime.Now;
            try
            {
                using (FileStream ZipFile = File.Create(topDirName + ZipedFileName))
                {
                    using (ZipOutputStream s = new ZipOutputStream(ZipFile))
                    {
                        if (password != null && password.Length > 0)
                            s.Password = password;

                        if (comment != null && comment.Length > 0)
                            s.SetComment(comment);

                        s.SetLevel(CompressionLevel); // 0 - means store only to 9 - means best compression  

                        for (int i = 0; i < fileNameToZip.Length; i++)
                        {

                            var isHave = false;
                            if (Directory.Exists(Path.Combine(topDirName, fileNameToZip[i])))
                            {
                                isHave = true;
                            }

                            if (File.Exists(Path.Combine(topDirName, fileNameToZip[i])))
                            {
                                isHave = true;
                            }

                            if (!isHave)
                                continue;

                            using (FileStream fs = File.OpenRead(Path.Combine(topDirName, fileNameToZip[i])))   //打开待压缩文件  
                            {
                                byte[] buffer = new byte[fs.Length];
                                fs.Read(buffer, 0, buffer.Length);      //读取文件流  
                                ZipEntry entry = new ZipEntry(fileNameToZip[i]);    //新建实例  
                                entry.DateTime = time;
                                entry.Size = fs.Length;
                                fs.Close();
                                s.PutNextEntry(entry);
                                s.Write(buffer, 0, buffer.Length);
                            }
                        }
                        s.Finish();
                        s.Close();
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }


        /// <summary>
        /// 文本写入
        /// </summary>
        /// <param name="path"></param>
        /// <param name="content"></param>
        /// <param name="fileName"></param>
        public static void WriteText(string path, string pathbf, DataTable dt, string fileName)
        {
            try
            {
                StreamWriter sw = File.CreateText(path + fileName + ".txt");
                StreamWriter swbf = null;
                if (!string.IsNullOrEmpty(pathbf))
                {
                    swbf = File.CreateText(pathbf + fileName + ".txt");
                }
                foreach (DataRow dataRow in dt.Rows)
                {
                    //ArrayList集合中添加键值
                    sw.WriteLine(json.tojson(DataRowToDic(dataRow, dt.Columns)));
                    if (!string.IsNullOrEmpty(pathbf))
                    {
                        swbf.WriteLine(json.tojson(DataRowToDic(dataRow, dt.Columns)));
                    }
                }
                sw.Close();
                if (!string.IsNullOrEmpty(pathbf))
                {
                    swbf.Close();
                }
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
            }
        }


        public static Dictionary<string, object> DataRowToDic(DataRow dataRow, DataColumnCollection dcc)
        {
            Dictionary<string, object> dictionary = new Dictionary<string, object>();  //实例化一个参数集合
            foreach (DataColumn dataColumn in dcc)
            {
                if (dataRow[dataColumn.ColumnName].ToString() != "")
                {
                    if (dataRow[dataColumn.ColumnName] is DateTime)
                        dictionary.Add(dataColumn.ColumnName, Convert.ToDateTime(dataRow[dataColumn.ColumnName]).ToString("yyyy-MM-dd HH:mm:ss"));
                    else
                    {
                        dictionary.Add(dataColumn.ColumnName, dataRow[dataColumn.ColumnName].ToString());
                    }
                }
                else
                {
                    dictionary.Add(dataColumn.ColumnName, "");
                }
            }
            return dictionary;
        }

        /// <summary>
        /// 创建根目录下的文件夹
        /// </summary>
        /// <param name="filePath"></param>
        public static void CreateFile(string filePath)
        {
            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + filePath) == false)//如果不存在就创建file文件夹
            {
                Directory.CreateDirectory(AppDomain.CurrentDomain.BaseDirectory + filePath);
            }
        }


        /// <summary>
        /// 计算文件的 MD5 值
        /// </summary>
        /// <param name="fileName">要计算 MD5 值的文件名和路径</param>
        /// <returns>MD5 值16进制字符串</returns>
        public static string MD5File(string fileName)
        {
            return HashFile(fileName, "md5");
        }

        /// <summary>
        /// 计算文件的哈希值
        /// </summary>
        /// <param name="fileName">要计算哈希值的文件名和路径</param>
        /// <param name="algName">算法:sha1,md5</param>
        /// <returns>哈希值16进制字符串</returns>
        private static string HashFile(string fileName, string algName)
        {
            if (!System.IO.File.Exists(fileName))
                return string.Empty;

            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            byte[] hashBytes = HashData(fs, algName);
            fs.Close();
            return ByteArrayToHexString(hashBytes);
        }


        /// <summary>
        /// 字节数组转换为16进制表示的字符串
        /// </summary>
        public static string ByteArrayToHexString(byte[] buf)
        {
            string returnStr = "";
            if (buf != null)
            {
                for (int i = 0; i < buf.Length; i++)
                {
                    returnStr += buf[i].ToString("X2");
                }
            }
            return returnStr;
        }

        /// <summary>
        /// 计算哈希值
        /// </summary>
        /// <param name="stream">要计算哈希值的 Stream</param>
        /// <param name="algName">算法:sha1,md5</param>
        /// <returns>哈希值字节数组</returns>
        private static byte[] HashData(Stream stream, string algName)
        {
            HashAlgorithm algorithm;
            if (algName == null)
            {
                throw new ArgumentNullException("algName 不能为 null");
            }
            if (string.Compare(algName, "sha1", true) == 0)
            {
                algorithm = SHA1.Create();
            }
            else
            {
                if (string.Compare(algName, "md5", true) != 0)
                {
                    throw new Exception("algName 只能使用 sha1 或 md5");
                }
                algorithm = MD5.Create();
            }
            return algorithm.ComputeHash(stream);
        }

        /// <summary>
        /// 获取字符串MD5值
        /// </summary>
        /// <param name="sDataIn"></param>
        /// <returns></returns>
        public static string GetMD5(string sDataIn)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] bytValue, bytHash;
            bytValue = System.Text.Encoding.UTF8.GetBytes(sDataIn);
            bytHash = md5.ComputeHash(bytValue);
            md5.Clear();
            string sTemp = "";
            for (int i = 0; i < bytHash.Length; i++)
            {
                sTemp += bytHash[i].ToString("X").PadLeft(2, '0');
            }
            return sTemp.ToLower();
        }

    }
    public class json
    {
        public static string tojson(object val)
        {
            try { return JsonConvert.SerializeObject(val); }
            catch { return null; }
        }

        public static T toobject<T>(string json)
        {
            try { return JsonConvert.DeserializeObject<T>(json); }
            catch { return default(T); }
        }
    }
}
